﻿using System;
using System.Collections.Generic;
using System.Linq;
using Rhizome.Contract;
using Rhizome.Contract.Diag;
using Rhizome.Model.Validation;

namespace Rhizome.Model
{
	public abstract class ActiveAutomatonBase<TState, TPlant> : AutomatonBase<TState, TPlant>, IDisposable
		where TState : class, IIdentityAccessor<object>
	{
		private bool _disposed;

		public IActiveObjectHost ActiveObjectHost
		{
			get { return GetValue(ActiveObjectHostProperty); }
			set { SetValue(ActiveObjectHostProperty, value); }
		}

		#region Overrides of AutomatonBase<TState,TPlant>

		public override sealed T GetValue<T>(RhizomeProperty<T> property)
		{
			if (ReferenceEquals(property, SynchronizationContextProperty))
				return (T)((object)(ActiveObjectHost.SynchronizationContext));

			return base.GetValue(property);
		}

		#endregion

		#region IDisposable Members

		public void Dispose()
		{
		    Dispose(true);
            GC.SuppressFinalize(this);
		}

	    private void Dispose(bool disposing)
	    {
            if (disposing == false) return;

            lock (this)
	        {
	            if (_disposed) return;
	            _disposed = true;
	        }

	        IActiveObjectHost value;
	        if (TryGetInternalValue(ActiveObjectHostProperty, out value) == false) return;

	        UnsetValue(ActiveObjectHostProperty);
	        if (value != null) value.Dispose();
	    }

	    #endregion

		#region Overrides of AutomatonBase<TState,TPlant>

		public override void CastEvent(object source, object @event)
		{
			ActiveObjectHost.SynchronizationContext.Post(state => BaseCastEvent(source, @event), null);
		}

		private void BaseCastEvent(object source, object @event)
		{
			base.CastEvent(source, @event);
		}

		#endregion

		protected override void OnStart()
		{
			ActiveObjectHost.Start();
			base.OnStart();
		}

		#region Validation

	    public override IEnumerable<IValidationResult> GetValidationResults()
		{
            return base.GetValidationResults().Concat(ActiveObjectHostErrors());
		}

		private IEnumerable<IValidationResult> ActiveObjectHostErrors()
		{
			if (ActiveObjectHost == null)
				yield return ValidationResult.ActiveObjectHostIsNull;
		}

		#endregion
	}

	public class ActiveAutomaton : ActiveAutomatonBase<IIdentityAccessor<object>, object>
	{
		
	}
}